package ldh.im.fxbase.dao;

import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.data.pojo.ext.ImUserExt;
import ldh.im.fxbase.data.pojo.status.ImUserStatus;
import ldh.im.fxbase.util.DbUtil;
import ldh.im.util.ConfigUtil;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class ImUserDao extends BaseDao {

    private static final String TABLE_NAME = "im_user";
    private static final String USER_COLUMNS = "u.id, u.userId, u.userName, u.mobile, u.motto, u.description, u.headImg, u.status statusValue, u.sex sexValue, " +
            "u.departmentCode, u.otherDepartmentCodes, u.ext1, u.ext2, u.firstLetter, u.createTime, u.updateTime";

    public List<ImUser> getUsers(int size) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_user u where u.status = ? limit 0, %s", USER_COLUMNS, size);
            List<ImUserExt> imUserExts = queryRunner.query(connection, sql, new BeanListHandler<>(ImUserExt.class), ImUserStatus.enable.getValue());
            return imUserExts.stream().map(u->u).collect(Collectors.toList());
        });
    }

    public List<ImUser> getDefaultUsers() throws SQLException {
        int userMaxSize = ConfigUtil.getInt("user.max.size", 1000);
        return getUsers(userMaxSize);
    }

    public ImUser getUserById(String id) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_user u where u.userId = ?", USER_COLUMNS);
            ImUserExt imUser = queryRunner.query(connection, sql, new BeanHandler<ImUserExt>(ImUserExt.class), id);
            return imUser;
        });
    }

    public List<ImUser> getUserByIds(List<String> ids) throws SQLException {
        if (ids.size() < 1) return new ArrayList<>();
        String userIdParam = ids.stream().map(id->String.format("'%s'", id)).collect(Collectors.joining(","));
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_user u where u.userId in (%s)", USER_COLUMNS, userIdParam);
            List<ImUserExt> imUsers = queryRunner.query(connection, sql, new BeanListHandler<ImUserExt>(ImUserExt.class));
            return imUsers.stream().map(u->u).collect(Collectors.toList());
        });
    }

    public void insertUser(ImUser imUser) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> resultSetHandler = new ScalarHandler();
            String sql = String.format("insert into im_user(userId, userName, mobile, motto, description, headImg, status, sex, departmentCode" +
                    ", ext1, ext2, firstLetter, createTime, updateTime) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            Long id = queryRunner.insert(connection, sql, resultSetHandler, imUser.getUserId(), imUser.getUserName(), imUser.getMotto(),
                    imUser.getDescription(), imUser.getHeadImg(), valueEnum(imUser.getStatus()), valueEnum(imUser.getSex()), imUser.getDepartmentCode(), imUser.getExt1(), imUser.getExt2(),
                    imUser.getFirstLetter(), imUser.getCreateTime(), imUser.getUpdateTime());
            imUser.setId(id);
            return imUser;
        });
    }

    public void batchInserts(List<ImUser> imUserList) throws SQLException {
        if (imUserList.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("insert into im_user(userId, userName, mobile, motto, description, headImg, status, sex, departmentCode" +
                    ", ext1, ext2, firstLetter, createTime, updateTime) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            Object[][] paras = imUserList.stream().map(u-> userToInsertArray(u)).toArray(Object[][]::new);
            List<Object[]> results = queryRunner.insertBatch(connection, sql, new ArrayListHandler(), paras);

            for(int i=0; i<results.size(); i++) {
                Long bigInteger = (Long) results.get(i)[0];
                imUserList.get(i).setId(bigInteger.longValue());
            }

            return imUserList;
        });
    }

    public void updateUser(ImUser imUser) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_user set userName = ?, mobile = ?, motto = ?, description = ?," +
                    " headImg = ?, status = ?, departmentCode = ?" +
                    ", ext1 = ?, ext2 = ?, firstLetter = ?, createTime = ?, updateTime = ? where userId = ?");
            Object[] paras = userToUpdateArray(imUser);
            queryRunner.update(connection, sql, paras);
            return imUser;
        });
    }

    public void batchUpdates(List<ImUser> imUserList) throws SQLException {
        if (imUserList.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_user set userName = ?, mobile = ?, motto = ?, description = ?," +
                    " headImg = ?, status = ?, departmentCode = ?, ext1 = ?, ext2 = ?, firstLetter = ?, createTime = ?, updateTime = ? where userId = ?");
            Object[][] paras = imUserList.stream().map(u-> userToUpdateArray(u)).toArray(Object[][]::new);
            queryRunner.batch(connection, sql, paras);
            return imUserList;
        });
    }

    private Object[] userToInsertArray(ImUser imUser) {
        return new Object[] {
                imUser.getUserId(), imUser.getUserName(), imUser.getMobile(), imUser.getMotto(),
                imUser.getDescription(), imUser.getHeadImg(), valueEnum(imUser.getStatus()), valueEnum(imUser.getSex()), imUser.getDepartmentCode(), imUser.getExt1(), imUser.getExt2(),
                imUser.getFirstLetter(), imUser.getCreateTime(), imUser.getUpdateTime()
        };
    }

    private Object[] userToUpdateArray(ImUser imUser) {
        return new Object[] {
                imUser.getUserName(), imUser.getMobile(), imUser.getMotto(),
                imUser.getDescription(), imUser.getHeadImg(), valueEnum(imUser.getStatus()), imUser.getDepartmentCode(), imUser.getExt1(), imUser.getExt2(),
                imUser.getFirstLetter(), imUser.getCreateTime(), imUser.getUpdateTime(), imUser.getUserId()
        };
    }
}
